package com.study.forumsystemproject.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.ICaptcha;
import com.study.forumsystemproject.common.Result;
import com.study.forumsystemproject.common.ResultCode;
import com.study.forumsystemproject.constant.Constants;
import com.study.forumsystemproject.dao.UserMapper;
import com.study.forumsystemproject.exception.ApplicationException;
import com.study.forumsystemproject.model.LoginInfo;
import com.study.forumsystemproject.model.User;
import com.study.forumsystemproject.service.IUserService;
import com.study.forumsystemproject.utils.MD5Util;
import com.study.forumsystemproject.utils.UUidUtil;
import com.study.forumsystemproject.utils.UrlUtil;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.List;

/**
 * program: forum-system-project
 * <p>
 * description: 注册
 * <p>
 * author: xiaoxie
 * <p>
 * create: 2024-08-15 17:16
 **/
@Service
@Slf4j
public class UserImpl implements IUserService {
    @Autowired
    private UserMapper userMapper;
    @Override
    public void register(User user) {
        //校验参数
        if(user.getUsername() == null || user.getNickname() == null
                || user.getPassword() == null|| user.getSalt() == null) {
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            throw new ApplicationException(Result.fail(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        User user1 = userMapper.selectByUsername(user.getUsername());
        //用户是否存在的校验
        if(user1 != null) {
            log.warn(ResultCode.FAILED_USER_EXISTS.toString());
            throw new ApplicationException(Result.fail(ResultCode.FAILED_USER_EXISTS));
        }
        //两次密码是否相同
        if(!user.getPassword().equals(user.getVerifyPassword())) {
            log.warn(ResultCode.FAILED_TWO_PWD_NOT_SAME.toString());
            throw new ApplicationException(Result.fail(ResultCode.FAILED_TWO_PWD_NOT_SAME));
        }
        //开始插入
        int row = userMapper.insert(user);
        if(row != 1) {
            log.warn("用户插入失败,user name" + user.getUsername());
            throw new ApplicationException(Result.fail(ResultCode.FAILED_CREATE));
        }
    }

    @Override
    public LoginInfo login(LoginInfo user,HttpSession session) {
        //校验参数
        if(!StringUtils.hasLength(user.getUsername())
                || !StringUtils.hasLength(user.getPassword())) {
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            throw new ApplicationException(Result.fail("输入框禁止为空,请重新输入"));
        }
        //用户是否存在
        User login = userMapper.selectByUsername(user.getUsername());
        if(login == null) {
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS+"username"+user.getUsername());
            throw new ApplicationException(Result.fail("用户不存在,请注册"));
        }
        //校验密码是否正确
        Boolean verify = MD5Util.verify(user.getPassword(), login.getSalt(), login.getPassword());
        if(!verify) {
            log.info(ResultCode.FAILED_LOGIN.toString());
            throw new ApplicationException(Result.fail(ResultCode.FAILED_LOGIN));
        }
        //校验验证码是否正确
        LoginInfo attribute = (LoginInfo) session.getAttribute(Constants.KEY);

        log.info(attribute.getCode());
        log.info(user.getCode());
        if(attribute == null) {
            log.warn(ResultCode.ERROR_SERVICES.toString());
            throw new ApplicationException(Result.fail("登录失败,请刷新设备"));
        }
        if(!user.getCode().equalsIgnoreCase(attribute.getCode())) {
            log.warn(ResultCode.FAILED_NOT_CAPTCHA.toString());
            throw new ApplicationException(Result.fail(ResultCode.FAILED_NOT_CAPTCHA));
        }
        if(attribute.getDate() - System.currentTimeMillis() > Constants.VALID_TIME) {
            log.warn(ResultCode.FAILED_FAILURE_CAPTCHA.toString());
            throw new ApplicationException(Result.fail(ResultCode.FAILED_FAILURE_CAPTCHA));
        }
        LoginInfo loginInfo = new LoginInfo();
        loginInfo.setUsername(login.getUsername());
        loginInfo.setPassword(login.getPassword());
        loginInfo.setId(login.getId());
        loginInfo.setState(login.getState());
        return loginInfo;
    }
    /**
     * Description: 生成验证码.
     * Param: session
     * @param response
     * return: void
     * Author: xiaoxie
     * Date: 12:00 2024/8/16
    */
    public void getCaptcha(HttpSession session, HttpServletResponse response) {
          log.info("getCaptcha session:{}",session);
        log.info("getCaptcha response:{}",response);
        ICaptcha captcha = CaptchaUtil.createLineCaptcha(Constants.width, Constants.height);
        try {
            captcha.write(response.getOutputStream());
            //禁止缓存
            response.setHeader("Prama", "No-cache");
            //设置返回的格式
            response.setContentType("image/jpeg");
            //打印验证码
            log.info(captcha.getCode());
            //存储Session
            LoginInfo loginInfo = new LoginInfo();
            loginInfo.setCode(captcha.getCode());
            loginInfo.setDate(System.currentTimeMillis());
            session.setAttribute(Constants.KEY, loginInfo);
            response.getOutputStream().close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Description: 通过ID获取User对象
     * Param: user id
     * return: user对象
     * Author: xiaoxie
     * Date: 19:52 2024/8/16
    */
    @Override
    public User getUserInfo(Long id) {
        log.info("getUserInfo session:{}",id);
        //校验ID
        if(id == null) {
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            throw new ApplicationException(Result.fail(ResultCode.FAILED_PARAMS_VALIDATE));
        }
       return userMapper.selectByPrimaryKey(id);
    }

    /**
     * Description: 通过id添加对应对象的文章数量
     * Param: user id 文章count
     * return: void
     * Author: xiaoxie
     * Date: 11:03 2024/8/17
    */
    @Override
    public void addOneArticleCountById(Long id,Integer count) {
        //参数校验
        if(id == null || count == null) {
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE+ "user id : " +id);
            throw new ApplicationException(Result.fail(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        //创建更新对象
        User updateUser = new User();
        updateUser.setId(id);
        updateUser.setArticleCount(count + 1);
        int row = userMapper.updateByPrimaryKeySelective(updateUser);
        //结果校验
        if(row != 1) {
            log.warn(ResultCode.FAILED_CREATE.toString());
            throw new ApplicationException(Result.fail(ResultCode.FAILED_CREATE));
        }
    }
    /**
     * Description: 通过id删除对应对象的文章数量
     * Param: user id 文章count
     * return: void
     * Author: xiaoxie
     * Date: 11:03 2024/8/17
     */
    @Override
    public void subOneArticleCountById(Long id) {
        //参数校验
        if(id == null) {
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE+ "user id : " +id);
            throw new ApplicationException(Result.fail(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        //获取用户对象
        User user = userMapper.selectByPrimaryKey(id);
        if(user == null) {
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString());
            throw new ApplicationException(Result.fail(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        //创建更新对象
        User updateUser = new User();
        updateUser.setId(id);
        updateUser.setArticleCount(user.getArticleCount() - 1);
        if(user.getArticleCount() - 1 < 0) {
            updateUser.setArticleCount(0);
        }
        int row = userMapper.updateByPrimaryKeySelective(updateUser);
        //结果校验
        if(row != 1) {
            log.warn(ResultCode.FAILED_CREATE.toString());
            throw new ApplicationException(Result.fail(ResultCode.FAILED_CREATE));
        }
    }

    @Override
    public void modifyUser(User user) {

        //校验参数
        if(user == null || user.getId() == null || user.getId() < 0) {
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            throw new ApplicationException(Result.fail(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        //根据id查看数据库中是否存在对象
        User oldUser = userMapper.selectByPrimaryKey(user.getId());
        if(oldUser == null || oldUser.getDeleteFlag() == 1) {
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString());
            throw new ApplicationException(Result.fail(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        //构造一个标志位确认是否有修改user对象
        Boolean checkModify = false;
        //开始构造对象
        User updateUser = new User();
        updateUser.setId(user.getId());
        //判断是否修改用户名
        if(user.getUsername() != null && !user.getUsername().equals(oldUser.getUsername())) {
            //判断数据库是否有相同的用户名
            User selectedByUsername = userMapper.selectByUsername(user.getUsername());
            if(selectedByUsername != null) {
                log.warn(ResultCode.FAILED_USER_EXISTS.toString());
                throw new ApplicationException(Result.fail(ResultCode.FAILED_USER_EXISTS));
            }
            //不存在就可以修改
            updateUser.setUsername(user.getUsername());
            checkModify = true;
        }
        //判断是否修改昵称
        if(user.getNickname() != null && !user.getNickname().equals(oldUser.getNickname())) {
            updateUser.setNickname(user.getNickname());
            checkModify = true;
        }
        //判断邮箱是否修改
        if(user.getEmail() != null && !user.getEmail().equals(oldUser.getEmail())) {
            updateUser.setEmail(user.getEmail());
            checkModify = true;
        }
        //判断电话号码是否修改
        if(user.getPhoneNum() != null && !user.getPhoneNum().equals(oldUser.getPhoneNum())) {
            updateUser.setPhoneNum(user.getPhoneNum());
            checkModify = true;
        }
        //判断简介是否修改
        if(user.getRemark() != null && !user.getRemark().equals(oldUser.getRemark())) {
            updateUser.setRemark(user.getRemark());
            checkModify = true;
        }
        //判断性别是否修改
        if(user.getGender() != null && !user.getGender().equals(oldUser.getGender())) {
            if(user.getGender() > 2 || user.getGender() < 0) {
                updateUser.setGender(2);
            }
            updateUser.setGender(user.getGender());
            checkModify = true;
        }
        //判断头像是否修改
        if(user.getAvatarUrl() != null && !user.getAvatarUrl().equals(oldUser.getAvatarUrl())) {
            //判断url是否有效
            boolean urlReachable = UrlUtil.isURLReachable(user.getAvatarUrl());
            if(urlReachable) {
                updateUser.setAvatarUrl(user.getAvatarUrl());
                checkModify = true;
            }else {
                log.warn(ResultCode.FAILED_URL_NOT_EXISTS.toString());
                throw new ApplicationException(Result.fail(ResultCode.FAILED_URL_NOT_EXISTS));
            }
        }
        if(checkModify) {
            int row = userMapper.updateByPrimaryKeySelective(updateUser);
            if(row != 1) {
                log.warn(ResultCode.ERROR_SERVICES.toString());
                throw new ApplicationException(Result.fail(ResultCode.ERROR_SERVICES));
            }
        }
    }


    @Override
    public void modifyPassword(Long id, String oldPassword, String newPassword) {
        if(id == null || !StringUtils.hasLength(oldPassword)
           || !StringUtils.hasLength(newPassword)) {
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            throw new ApplicationException(Result.fail(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        //根据用户id获得用户对象
        User user = userMapper.selectByPrimaryKey(id);
        if(user == null || user.getDeleteFlag() == 1) {
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString());
            throw new ApplicationException(Result.fail(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        //获取盐值
        String salt = user.getSalt();
        Boolean verify = MD5Util.verify(oldPassword, salt, user.getPassword());
        if(!verify) {
            log.warn(ResultCode.FAILED_LOGIN.toString());
            throw new ApplicationException(Result.fail(ResultCode.FAILED_LOGIN));
        }
        //重新构造盐值和密码
        String uuid = UUidUtil.getUUID();
        String entryPassword = MD5Util.md5AndSalt(newPassword,uuid);
        User updateUser = new User();
        updateUser.setId(id);
        updateUser.setPassword(entryPassword);
        updateUser.setSalt(uuid);
        int row = userMapper.updateByPrimaryKeySelective(updateUser);
        if(row != 1) {
            log.warn(ResultCode.ERROR_SERVICES.toString());
            throw new ApplicationException(Result.fail(ResultCode.ERROR_SERVICES));
        }

    }
}
